use std::{collections::HashMap, sync::Arc};

use manage::{SiminkManage, SiminkQuitCause};
use monitor::{CompleterSuggestion, MonError, Monitor, MonitorCommand};

struct ExitCommand {
    manage: Arc<SiminkManage>,
}

impl MonitorCommand for ExitCommand {
    fn mon_protocol_exec(&self, _: &monitor::Protocol) -> monitor::MonResult<monitor::Protocol> {
        Err(MonError::PermProtocol)
    }

    fn mon_readline_arg_type(&self) -> Option<&'static str> {
        Some("")
    }

    fn mon_readline_completer(&self, _: &[&str], _: bool) -> Option<CompleterSuggestion> {
        None
    }

    fn mon_readline_exec(
        &self,
        _: &HashMap<String, String>,
        _: &monitor::MonitorPrinter,
    ) -> monitor::MonResult<()> {
        self.manage.request_simink_quit(SiminkQuitCause::HostMonitorQuit);
        Ok(())
    }

    fn mon_readline_help(&self) -> String {
        String::from("退出 simink")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("执行该命令程序退出"))
    }
}

// 程序退出
pub(crate) fn monitor_command_exit_register(mon: &Monitor, manage: Arc<SiminkManage>) {
    mon.register_command("exit", Arc::new(ExitCommand { manage })).unwrap();
}

struct QuitRlCommand {
    manage: Arc<SiminkManage>,
}

impl MonitorCommand for QuitRlCommand {
    fn mon_protocol_exec(&self, _: &monitor::Protocol) -> monitor::MonResult<monitor::Protocol> {
        Err(monitor::MonError::PermProtocol)
    }

    fn mon_readline_arg_type(&self) -> Option<&'static str> {
        Some("")
    }

    fn mon_readline_completer(&self, _: &[&str], _: bool) -> Option<CompleterSuggestion> {
        None
    }

    fn mon_readline_exec(
        &self,
        _: &HashMap<String, String>,
        _: &monitor::MonitorPrinter,
    ) -> monitor::MonResult<()> {
        self.manage.set_readline_wait();
        Ok(())
    }

    fn mon_readline_help(&self) -> String {
        String::from("退出命令行")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("执行该命令退出命令行, protocol 不能执行该命令"))
    }
}

// readline 进入等待状态
pub(crate) fn monitor_command_quit_rl_register(mon: &Monitor, manage: Arc<SiminkManage>) {
    mon.register_command("quit_rl", Arc::new(QuitRlCommand { manage })).unwrap();
}

struct RunRlCommand {
    manage: Arc<SiminkManage>,
}

impl MonitorCommand for RunRlCommand {
    fn mon_protocol_exec(&self, _: &monitor::Protocol) -> monitor::MonResult<monitor::Protocol> {
        self.manage.notify_readline_run();
        let hash = HashMap::new();
        Ok(hash)
    }

    fn mon_readline_arg_type(&self) -> Option<&'static str> {
        Some("")
    }

    fn mon_readline_completer(&self, _: &[&str], _: bool) -> Option<CompleterSuggestion> {
        None
    }

    fn mon_readline_exec(
        &self,
        _: &HashMap<String, String>,
        _: &monitor::MonitorPrinter,
    ) -> monitor::MonResult<()> {
        Err(monitor::MonError::PermOperation)
    }

    fn mon_readline_help(&self) -> String {
        String::from("protocol 通知命令行运行")
    }

    fn mon_readline_long_help(&self) -> Option<String> {
        Some(String::from("通过 protocol 启动命令行运行, 命令行执行无效果"))
    }
}

// 通过 protocol 重新启动命令行
pub(crate) fn monitor_command_run_rl_register(mon: &Monitor, manage: Arc<SiminkManage>) {
    mon.register_command("run_rl", Arc::new(RunRlCommand { manage })).unwrap();
}
